/* 
 * $Id$
 *
 * UMKC Robotics 2009
 *
 *
 *
 * TODO: need to do bounds checking on all argv indexes.
**/

#include <stdio.h>
#include <stdarg.h>

#include "err.h"
extern int err;

#include "iobase.h"
#include "iopublic.h"

/* bot io subsys functions */
static int bio_init();
static inline int bio_reset();

/* bioctl functions */
static inline int bioctl_load(BotDeviceIdx);
static inline int bioctl_reset(BotDeviceIdx);
static inline int bioctl_unload(BotDeviceIdx);
static inline int bioctl_clone(BotDeviceIdx, BotDeviceIdx);
static int breadf(BotDeviceIdx, const char*, ... );
static int bwritef(BotDeviceIdx, const char*, ... );

/* the bio (bot io) object - this loads all the necessary
 * callbacks for avr stdio to work */
const BotIo bio = {
  
  &bio_init,
  &bio_reset

};

/* the bioctl 'object' - all io goes thru here...  */
const BotIoctl bioctl = {

  &bioctl_load,
  &bioctl_reset,
  &bioctl_unload,
  &bioctl_clone,
  &breadf,
  &bwritef

};

/* the bdev array.  An array of devices initialized to
 * zeros. NB - making this an array of pointers to BotDevice
 * would save some space as you could 'alias' LCD as BSTDOUT
 * simply by copying the LCD pointer into the BSTDOUT - and
 * then BSTDOUT and LCD are the same w/o having to dick with
 * the callback pointers.  
 *
 * For now, the clone() function takes care of aliasing one
 * device to another..*/
BotDevice bdev[DEV_MAX] = { { 0 } };  


/* the function that fills up bdev[].  must be called before
 * all other io calls */
static int bio_init() {

#ifdef WITH_IOSTDOUT
#include "iostdout.h"

  bdev[BSTDOUT].init = &stdout_init;
  bdev[BSTDOUT].reset = &stdout_reset;
  bdev[BSTDOUT].destroy = &stdout_destroy;
  bdev[BSTDOUT].read = NULL;
  bdev[BSTDOUT].write = &stdout_write;

#endif

#ifdef WITH_IOSTDERR
#include "iostderr.h"

  bdev[BSTDERR].init = &stderr_init;
  bdev[BSTDERR].reset = &stderr_reset;
  bdev[BSTDERR].destroy = &stderr_destroy;
  bdev[BSTDERR].read = NULL;
  bdev[BSTDERR].write = &stderr_write;

#endif

#ifdef WITH_IOSTDIN
#include "iostdin.h"

  bdev[BSTDIN].init = &stdin_init;
  bdev[BSTDIN].reset = &stdin_reset;
  bdev[BSTDIN].destroy = &stdin_destroy;
  bdev[BSTDIN].read = &stdin_read;
  bdev[BSTDIN].write = NULL;

#endif

#ifdef WITH_IOLCD
#include "iolcd.h"

  bdev[BLCD].init = &lcd_init;
  bdev[BLCD].reset = &lcd_reset;
  bdev[BLCD].destroy = &lcd_destroy;
  bdev[BLCD].read = NULL;
  bdev[BLCD].write = &lcd_write;

#endif

  return(err=E_NO_ERROR);

} /* end bio_init() */


/* a completely pointless function */
static inline int bio_reset() {

  bio_init();
  return(err=E_NO_ERROR);

}


/* call the driver's init() function unless NULL  */
static inline int bioctl_load(BotDeviceIdx idx) {

  if( bdev[idx].init != NULL )
    return( bdev[idx].init() );
  else 
    return (err = E_NULL_CALLBACK);

}

/* call the driver's reset() function unless NULL */
static inline int bioctl_reset(BotDeviceIdx idx) {

  if( bdev[idx].reset != NULL )
    return( bdev[idx].reset() );
  else 
    return (err = E_NULL_CALLBACK);
}

/* call the driver's destroy() function unless NULL */
static inline int bioctl_unload(BotDeviceIdx idx) {

  if( bdev[idx].destroy != NULL )
    return( bdev[idx].destroy() );
  else 
    return (err = E_NULL_CALLBACK);

}

/* create a (shallow) copy of a device */
static inline int bioctl_clone(BotDeviceIdx from, BotDeviceIdx to) {

  bdev[to].dev = bdev[from].dev;
  bdev[to].init = bdev[from].init;
  bdev[to].reset = bdev[from].reset;
  bdev[to].destroy = bdev[from].destroy;
  bdev[to].read = bdev[from].read;
  bdev[to].write = bdev[from].write;

  return(E_NO_ERROR);

}
  

/* do a vfscanf() - dependent on some reasonable stdio
 * implementation */
static int breadf(BotDeviceIdx idx, const char* fmt, ... ) {

  int ret;
  va_list ap;
  va_start(ap, fmt);

#if defined(WITH_AVRLIBC)
  if( bdev[idx].read != NULL )
    ret = vfscanf(&bdev[idx].dev, fmt, ap);
  else 
    ret = E_NULL_CALLBACK;
#else 
  ret = vfscanf(bdev[idx].dev, fmt, ap);
#endif

  va_end(ap);
  return(ret);

}

/* do a vprintf() - dependent on some reasonable stdio
 * implementation */
static int bwritef(BotDeviceIdx idx, const char* fmt, ... ) {

  int ret;
  va_list ap;
  va_start(ap, fmt);

#if defined(WITH_AVRLIBC)
  if( bdev[idx].read != NULL )
    ret = vfprintf(&bdev[idx].dev, fmt, ap);
  else 
    ret = E_NULL_CALLBACK;
#else 
  ret = vfprintf(bdev[idx].dev, fmt, ap);
#endif

  va_end(ap);
  return(ret);

}
